/*
 * colas.c
 *
 *  Created on: 27/09/2011
 *      Author: utn_so
 */

#include "algoritmoPPD.h"

void PONER_EN_COLA_SSTF(t_sector sector, cola C)

{
	cola Cola;
	Cola = C;
	if ((*Cola) == NULL)
	{
		(*Cola) = (primero) malloc(sizeof(nodo));
		(*Cola)->elemento = sector;
		(*Cola)->siguiente = NULL;
	}
	else
	{
		primero actual = NULL;
		primero ptr = NULL;
		actual = *Cola;
		if ((actual->siguiente) != NULL)
		{

			if (abs(posActualCabezal.cilindro - sector.direccion.cilindro)
					< abs(
							posActualCabezal.cilindro
									- (actual)->elemento.direccion.cilindro))
			{
				ptr = (nodo*) malloc(sizeof(nodo));
				ptr->elemento = sector;
				ptr->siguiente = actual;
				*Cola = ptr;
				return;
			}
			else
			{
				while (abs(
						actual->elemento.direccion.cilindro
								- sector.direccion.cilindro)
						> abs(
								(actual)->siguiente->elemento.direccion.cilindro
										- (actual)->elemento.direccion.cilindro))
				{
					actual = actual->siguiente;
					if ((actual->siguiente) == NULL
					)
						break;
				}
				if (((actual)->siguiente) != NULL)
				{
					if (abs(
							(actual)->elemento.direccion.cilindro
									- sector.direccion.cilindro)
							== abs(
									(actual)->siguiente->elemento.direccion.cilindro
											- (actual)->elemento.direccion.cilindro))
					{
						(actual) = (actual)->siguiente; // Si la cercania es igual decide por FIFO
					}
				}
			}
		}
		ptr = (nodo*) malloc(sizeof(nodo));
		ptr->elemento = sector;
		ptr->siguiente = (actual)->siguiente;
		(actual)->siguiente = ptr;
	}
}

void ORDENAR_ASCENDENTE_SCAN(t_sector sector, nodo** cola)
{
	nodo *actual, *ptr;
	actual = *cola;

	if (actual == NULL)
	{
		actual = (nodo *) malloc(sizeof(nodo));
		actual->elemento = sector; // insertar primero
		actual->siguiente = NULL;
		*cola = actual;
		//ptr = (nodo *) malloc(sizeof(nodo)); // Acá pongo el último sector
		//ptr->elemento.direccion.cilindro = configuracion.cilindro - 1;
		//ptr->elemento.direccion.sector = configuracion.sector - 1;
		//ptr->elemento.direccion.cabeza = configuracion.cabeza - 1;
		//ptr->elemento.type = Scan;
		//ptr->siguiente = actual->siguiente;
		//(*cola)->siguiente = ptr;
	}
	else
	{
		while (actual != NULL
				&& actual->elemento.direccion.cilindro
						< sector.direccion.cilindro)
		{
			if (actual->siguiente == NULL
			)
				break;
			actual = actual->siguiente;

		}

		if (sector.direccion.cilindro > actual->elemento.direccion.cilindro)
		{
			ptr = (nodo *) malloc(sizeof(nodo));
			ptr->elemento = sector;
			ptr->siguiente = actual->siguiente;
			actual->siguiente = ptr;
		}
		else
		{
			ptr = (nodo *) malloc(sizeof(nodo));
			ptr->elemento = actual->elemento;
			ptr->siguiente = actual->siguiente;
			actual->elemento = sector;
			actual->siguiente = ptr;
		}
	}
}

void ORDENAR_DESCENDENTE_SCAN(t_sector sector, nodo** cola)
{
	nodo *actual, *ptr;

	actual = *cola;

	if (actual == NULL)
	{
		actual = (nodo *) malloc(sizeof(nodo));
		actual->elemento = sector; // insertar primero
		actual->siguiente = NULL;
		*cola = actual;
		//ptr = (nodo *) malloc(sizeof(nodo)); // Acá pongo el primer elemento de la cola nro 1
		//ptr->elemento.direccion.cilindro = 0;
		//ptr->elemento.direccion.cabeza = 0;
		//ptr->elemento.direccion.sector = 0;
		//ptr->elemento.type = Scan;
		//ptr->siguiente = actual->siguiente;
		//(*cola)->siguiente = ptr;

	}
	else
	{
		while (actual != NULL
				&& actual->elemento.direccion.cilindro
						> sector.direccion.cilindro)
		{
			if (actual->siguiente == NULL
			)
				break;
			actual = actual->siguiente;

		}

		if (sector.direccion.cilindro < actual->elemento.direccion.cilindro)
		{
			ptr = (nodo *) malloc(sizeof(nodo));
			ptr->elemento = sector;
			ptr->siguiente = actual->siguiente;
			actual->siguiente = ptr;
		}
		else
		{
			ptr = (nodo *) malloc(sizeof(nodo));
			ptr->elemento = actual->elemento;
			ptr->siguiente = actual->siguiente;
			actual->elemento = sector;
			actual->siguiente = ptr;
		}
	}
}

void QUITAR_DE_COLA(t_sector *sector, cola C)
{
	primero actual = NULL;
	if (*C != NULL)
	{
		actual = *C;
		t_sector *sectorDeLaCola;
		sectorDeLaCola = &((*C)->elemento);
		memcpy(sector, sectorDeLaCola, sizeof(t_sector));
		(*C) = (actual)->siguiente;
		actual->siguiente = NULL;
		free(actual);
		actual = NULL;
	}
}

void QUITAR_DE_COLA_SCAN(t_sector *sector, t_colaSCAN* C)
{
	if (C->estado == ascendente)
	{
		QUITAR_DE_COLA(sector, &(C->colaAscendente));
		if (C->colaAscendente == NULL && C->colaDescendente != NULL
		)
			C->estado = descendente;
	}
	else
	{
		if (C->estado == descendente)
		{
			QUITAR_DE_COLA(sector, &(C->colaDescendente));
			if (C->colaDescendente == NULL && C->colaAscendente != NULL
			)
				C->estado = ascendente;
		}
	}
}

void PONER_EN_COLA_SCAN(t_sector sector, t_colaSCAN* C)
{
	t_sector inicio, fin;
	inicio.direccion.cilindro = 0;
	inicio.type = Scan;
	fin.direccion.cilindro = configuracion.cilindro - 1;
	fin.type = Scan;
	if (C->estado == ascendente)
	{
		if (C->colaAscendente != NULL)
		{
			if (sector.direccion.cilindro <= C->ultimoSacado.cilindro)
			{
				ORDENAR_DESCENDENTE_SCAN(sector, &(C->colaDescendente));
			}
			else
			{
				ORDENAR_ASCENDENTE_SCAN(sector, &(C->colaAscendente));
			}
		}
		else
		{
			ORDENAR_ASCENDENTE_SCAN(sector, &(C->colaAscendente));
		}
	}
	if (C->estado == descendente)
	{
		if (C->colaDescendente != NULL)
		{
			if (sector.direccion.cilindro >= C->ultimoSacado.cilindro)
			{
				ORDENAR_ASCENDENTE_SCAN(sector, &(C->colaAscendente));
			}
			else
			{
				ORDENAR_DESCENDENTE_SCAN(sector, &(C->colaDescendente));
			}
		}
		else
		{
			ORDENAR_DESCENDENTE_SCAN(sector, &(C->colaDescendente));
		}
	}
}

t_direccion_fisica ultimoElemento(nodo* cola)
{
	nodo* ptr;
	ptr = cola;
	while (ptr->siguiente != NULL)
		ptr = ptr->siguiente;
	return ptr->elemento.direccion;
}

void PONER_EN_COLA_NSTEP(t_sector sector, t_list* nstep)
{
	t_colaSCAN *nuevaCola;
	if (nstep->elements_count == 0)
	{
		nuevaCola = (t_colaSCAN*) malloc(sizeof(t_colaSCAN));
		nuevaCola->colaAscendente = NULL;
		nuevaCola->colaDescendente = NULL;
		nuevaCola->cantidad = 1;
		nuevaCola->estado = ascendente;
		nuevaCola->ultimoSacado.cabeza = 0;
		nuevaCola->ultimoSacado.cilindro = 0;
		nuevaCola->ultimoSacado.sector = 0;
		PONER_EN_COLA_SCAN(sector, nuevaCola);
		collection_list_add(nstep, (void *) nuevaCola);

	}
	else
	{
		t_colaSCAN* ultimaCola;
		ultimaCola = (t_colaSCAN*) collection_list_get(nstep,
				(nstep->elements_count - 1));
		if (ultimaCola->cantidad == configuracion.maxNSTEP)
		{
			nuevaCola = (t_colaSCAN*) malloc(sizeof(t_colaSCAN));
			nuevaCola->colaAscendente = NULL;
			nuevaCola->colaDescendente = NULL;
			nuevaCola->cantidad = 1;
			nuevaCola->ultimoSacado = ultimaCola->ultimoSacado;
			if (ultimaCola->estado == ascendente)
				nuevaCola->estado = descendente;
			if (ultimaCola->estado == descendente)
				nuevaCola->estado = ascendente;
			PONER_EN_COLA_SCAN(sector, nuevaCola);
			collection_list_add(nstep, (void *) nuevaCola);
		}
		else
		{
			PONER_EN_COLA_SCAN(sector, ultimaCola);
			ultimaCola->cantidad++;
		}
	}

}

void QUITAR_DE_COLA_NSTEP(t_sector *sector, t_list* nstep)
{
	if (colaActual->cantidad == 0)
	{
		free(colaActual);
		colaActual = NULL;
		if (nstep->elements_count > 1)
		{
			colaActual = (t_colaSCAN*) collection_list_remove(nstep, 0);
		}
		else
		{
			colaActual = (t_colaSCAN*) collection_list_get(nstep, 0);
		}

	}
	QUITAR_DE_COLA_SCAN(sector, colaActual);
	colaActual->ultimoSacado = sector->direccion;
	if (colaActual->estado == ascendente && colaActual->colaAscendente != NULL)
	{
		if (colaActual->colaAscendente->siguiente != NULL)
		{
			if (colaActual->colaAscendente->siguiente->elemento.direccion.cilindro
					== configuracion.cilindro - 1
					&& colaActual->colaAscendente->siguiente->elemento.type
							== Scan)
			{
				colaActual->estado = descendente;
			}
		}
	}
	else
	{
		if (colaActual->estado == descendente
				&& colaActual->colaDescendente != NULL)
		{
			if (colaActual->colaDescendente->siguiente != NULL)
			{
				if (colaActual->colaDescendente->siguiente->elemento.direccion.cilindro
						== 0
						&& colaActual->colaDescendente->siguiente->elemento.type
								== Scan)
				{
					colaActual->estado = ascendente;
				}
			}
		}
	}
	colaActual->cantidad--;
	if (colaActual->cantidad == 0 && nstep->elements_count == 1)
	{
		colaActual = (t_colaSCAN*) collection_list_remove(nstep, 0);
	}
}

uint32_t cantidadElementos(void* v_cola)
{
	uint32_t cantidad = 0;
	nodo* ptr;
	ptr = *((cola) v_cola);
	if (ptr != NULL)
	{
		while (ptr->siguiente != NULL)
		{
			ptr = ptr->siguiente;
			cantidad++;
		}
	}
	return cantidad;
}
